package top.archiesean.authorize.support.handler;

import cn.hutool.core.map.MapUtil;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.convert.converter.Converter;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
import org.springframework.security.oauth2.core.endpoint.DefaultOAuth2AccessTokenResponseMapConverter;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.util.CollectionUtils;
import top.archiesean.common.core.domain.R;
import top.archiesean.common.core.utils.resp.ResponseUtils;

import java.io.IOException;
import java.time.temporal.ChronoUnit;
import java.util.Map;

/**
 * @author ArchieSean
 * @description 认证成功处理器
 * @date 2024-01-05 07:36
 */
@Slf4j
public class AuthenticationSuccessEventHandler implements AuthenticationSuccessHandler {

    private final Converter<OAuth2AccessTokenResponse, Map<String, Object>> accessTokenResponseParametersConverter =
            new DefaultOAuth2AccessTokenResponseMapConverter();

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        OAuth2AccessTokenAuthenticationToken accessTokenAuthentication = (OAuth2AccessTokenAuthenticationToken) authentication;
        Map<String, Object> map = accessTokenAuthentication.getAdditionalParameters();
        if (MapUtil.isNotEmpty(map)) {
            //todo 根据需要是否进行日志埋点记录
            //此处，暂时让入，可在log模块当中从SecurityContextHolder取出用户等相关信息
            SecurityContextHolder.getContext().setAuthentication(accessTokenAuthentication);
        }
        //输出token
        sendAccessTokenResponse(response, accessTokenAuthentication);
    }

    private void sendAccessTokenResponse(HttpServletResponse response, OAuth2AccessTokenAuthenticationToken accessTokenAuthentication) {
        //token
        OAuth2AccessToken accessToken = accessTokenAuthentication.getAccessToken();
        //刷新令牌
        OAuth2RefreshToken refreshToken = accessTokenAuthentication.getRefreshToken();
        //扩展参数
        Map<String, Object> additionalParameters = accessTokenAuthentication.getAdditionalParameters();
        OAuth2AccessTokenResponse.Builder builder = OAuth2AccessTokenResponse.withToken(accessToken.getTokenValue())
                .tokenType(accessToken.getTokenType()).scopes(accessToken.getScopes());
        if (accessToken.getIssuedAt() != null && accessToken.getExpiresAt() != null) {
            builder.expiresIn(ChronoUnit.SECONDS.between(accessToken.getIssuedAt(), accessToken.getExpiresAt()));
        }
        if (refreshToken != null) {
            builder.refreshToken(refreshToken.getTokenValue());
        }
        if (!CollectionUtils.isEmpty(additionalParameters)) {
            builder.additionalParameters(additionalParameters);
        }
        OAuth2AccessTokenResponse accessTokenResponse = builder.build();
        //token数据
        Map<String, Object> tokenResponseParameters = this.accessTokenResponseParametersConverter.convert(accessTokenResponse);

        System.out.println(tokenResponseParameters);

        // 无状态 注意删除 context 上下文的信息
        SecurityContextHolder.clearContext();

        ResponseUtils.out(response, R.success(tokenResponseParameters));
    }
}
